#include "keyboard.h"
#include "gpio.h"

#define  KEY_DELAY  10  //中断去抖动间隔ms

volatile uint8_t  key;
// 行key_row 列key_col
uint8_t key_col, key_row = 0;


// A0-3外部中断 A9-12开漏输出
static void key_exti_mode(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    //Pin0、1、2、3为上拉输入，下降沿中断
    GPIO_InitStruct.Pin = KEY_ROW_0_Pin|KEY_ROW_1_Pin|KEY_ROW_2_Pin|KEY_ROW_3_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    //Pin9、10、11、12为开漏输出
    GPIO_InitStruct.Pin = KEY_COL_0_Pin|KEY_COL_1_Pin|KEY_COL_2_Pin|KEY_COL_3_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    // Pin9、10、11、12输出低电平
    HAL_GPIO_WritePin(GPIOA, KEY_COL_0_Pin|KEY_COL_1_Pin|KEY_COL_2_Pin|KEY_COL_3_Pin, GPIO_PIN_RESET);

    // 清除可能的挂起中断 
    __HAL_GPIO_EXTI_CLEAR_IT(KEY_ROW_0_Pin|KEY_ROW_1_Pin|KEY_ROW_2_Pin|KEY_ROW_3_Pin);
}

// 进入中断后切换GPIO状态
// A0-3开漏输出 A9-12上拉输入读取Pin值
static void key_change_mode(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    // Pin0、1、2、3开漏输出
    GPIO_InitStruct.Pin = KEY_ROW_0_Pin|KEY_ROW_1_Pin|KEY_ROW_2_Pin|KEY_ROW_3_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // Pin9、10、11、12为上拉输入
    GPIO_InitStruct.Pin = KEY_COL_0_Pin|KEY_COL_1_Pin|KEY_COL_2_Pin|KEY_COL_3_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    // Pin0、1、2、3开漏输出
    HAL_GPIO_WritePin(GPIOA, KEY_ROW_0_Pin|KEY_ROW_1_Pin|KEY_ROW_2_Pin|KEY_ROW_3_Pin, GPIO_PIN_RESET);
}

// 初始化矩阵键盘
void key_board_init(void)
{
    key_exti_mode();
    key = 0;
}

static uint8_t get_key_num(uint8_t num)//按键两引脚值相加（引脚只用到了前八个所以只有低 八位）
{
	switch(num)
	{
		case 0x11:key='0';break;
		case 0x12:key='1';break;
		case 0x14:key='2';break;
		case 0x18:key='3';break;
		case 0x21:key='4';break;
		case 0x22:key='5';break;
		case 0x24:key='6';break;
		case 0x28:key='7';break;
		case 0x41:key='8';break;
		case 0x42:key='9';break;
		case 0x44:key='A';break;
		case 0x48:key='B';break;
		case 0x81:key='C';break;
		case 0x82:key='D';break;
		case 0x84:key='E';break;		
		case 0x88:key='F';break;
	}
	return key;
}
//获取按键，返回0，没有键值，非0，获得键值
//该函数在中断中调用
uint8_t get_key(uint8_t key_row)
{
    uint8_t i = 0;
    uint8_t num = 0;
    key_col = 0;
	
    
	if(key_row)
	{
        // 切换IO模式
        key_change_mode();
        // 行key_row Pin0、1、2、3      列key_col Pin9、10、11、12
		for(i = 9; i <= 12; i++)
		{
            // 因为#define GPIO_PIN_9 (uint16_t)0x0200
			if(HAL_GPIO_ReadPin(KEY_COL_0_GPIO_Port, (uint16_t)(1u<<i)) == GPIO_PIN_RESET){
                key_col = 1 << (i - 9);
                num = key_col | key_row;
            }
		}
        key_exti_mode();
		return get_key_num(num);
	}
	else
	{
		return 0;
	}
}

// 行key_row Pin0、1、2、3      列key_col Pin9、10、11、12
// A0-3外部中断服务函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_PIN)
{
    // 略微延时去除抖动
    // HAL_Delay(KEY_DELAY);
    // 判断哪个GPIO产生了外部中断
    switch (GPIO_PIN)
    {
        case KEY_ROW_0_Pin:
            key_row = 0x10;
            break;
        case KEY_ROW_1_Pin:
            key_row = 0x20;
            break;
        case KEY_ROW_2_Pin:
            key_row = 0x40;
            break;
        case KEY_ROW_3_Pin:
            key_row = 0x80;
            break;
        
        default:
            key_row = 0;
            return;
    }

    //执行中断灯亮一下
    HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);

    // 获取键值
    c = get_key(key_row);
}

